package org.ai.demo.auth.config;

import javax.sql.DataSource;

import org.ai.demo.auth.config.exception.CustomWebResponseExceptionTranslator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    @Autowired
    AuthenticationManager authenticationManager;
    @Autowired
    RedisConnectionFactory redisConnectionFactory;
    @Autowired
    ApplicationContext applicationContext;
    @Autowired
    private DataSource dataSource;
    @Autowired
    CustomWebResponseExceptionTranslator myExceptionTranslator;
    @Value("${token.validity.seconds:2592000}")
    private int tokenValiditySeconds;
    
    @Bean
    public TokenStore tokenStore() {
        return new RedisTokenStore(redisConnectionFactory);
    }
    
    @Bean
    public ClientDetailsService clientDetails() {
        return new JdbcClientDetailsService(dataSource);
    }
    
    /**
	 * 配置 oauth_client_details【client_id和client_secret等】信息
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    	clients.withClientDetails(clientDetails());
    }

   
    /**
     * ClientCredentialsTokenEndpointFilter
     * 配置CheckEndpoint类的接口 oauth/check_token 无需经过过滤器过滤，默认值：denyAll()
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
        //允许表单认证
        oauthServer
        .allowFormAuthenticationForClients()
        //new BCryptPasswordEncoder()
        .passwordEncoder(new NoEncryptPasswordEncoder())//设置oauth_client_details中的密码编码器
        .tokenKeyAccess("permitAll()")
        .checkTokenAccess("isAuthenticated()");
    }
    
    
    @SuppressWarnings("unchecked")
	@Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints
                .tokenStore(tokenStore())
                .authenticationManager(authenticationManager)
                .allowedTokenEndpointRequestMethods(HttpMethod.POST);//HttpMethod.GET
        endpoints.tokenServices(defaultTokenServices());
        endpoints.exceptionTranslator(myExceptionTranslator);
    }
    

    /**
    * 自定义TokenServices,认证的token是存到redis里的
     */
    @Primary
    @Bean
    public DefaultTokenServices defaultTokenServices(){
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(tokenStore());
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setClientDetailsService(clientDetails());
        // token有效期自定义设置
        tokenServices.setAccessTokenValiditySeconds(tokenValiditySeconds);
        
        TokenEnhancer tokenEnhancer = new CustomerAccessTokenConverter(clientDetails());
        tokenServices.setTokenEnhancer(tokenEnhancer);
        return tokenServices;
    }

}
